#ifndef MATERIAL_HEADER_VIZMF_PROJECT
#define MATERIAL_HEADER_VIZMF_PROJECT


/*
  VizMF Material class
*/


class Material {
public:
  void setAmbient(const float a = 1.0, const float b = 1.0, const float c = 1.0, const float d = 1.0)
  {
    ambient_[0] = a; ambient_[1] = b; ambient_[2] = c; ambient_[3] = d;
  }
  void setAmbient(const float a[])
  {
    ambient_[0] = a[0]; ambient_[1] = a[1]; ambient_[2] = a[2]; ambient_[3] = a[3];
  }
  void setDiffuse(const float a = 1.0, const float b = 1.0, const float c = 1.0, const float d = 1.0)
  {
    diffuse_[0] = a; diffuse_[1] = b; diffuse_[2] = c; diffuse_[3] = d;
  }
  void setDiffuse(const float a[])
  {
    diffuse_[0] = a[0]; diffuse_[1] = a[1]; diffuse_[2] = a[2]; diffuse_[3] = a[3];
  }
  void setSpecular(const float a = 1.0, const float b = 1.0, const float c = 1.0, const float d = 1.0)
  {
    specular_[0] = a; specular_[1] = b; specular_[2] = c; specular_[3] = d;
  }
  void setSpecular(const float a[])
  {
    specular_[0] = a[0]; specular_[1] = a[1]; specular_[2] = a[2]; specular_[3] = a[3];
  }
  void setShininess(const float a = 32.0)
  {
    shininess_[0] = a;
  }
  Material() {setAmbient(); setDiffuse(); setSpecular(); setShininess();}
  Material(const float a, const float b, const float c, const float d)
  {
    setAmbient(a, b, c, d);
    setDiffuse(a, b, c, d);
    setSpecular();
    setShininess();
  }
  void setMaterial(const float a, const float b, const float c, const float d)
  {
    setAmbient(a, b, c, d);
    setDiffuse(a, b, c, d);
  }
  const float* ambient() const
  {
    return ambient_;
  }
  const float* diffuse() const
  {
    return diffuse_;
  }
  const float* specular() const
  {
    return specular_;
  }
  float shininess() const
  {
    return shininess_[0];
  }
  Material mix(const Material& other) const
  {
    Material mat;
    mat.setAmbient( (ambient_[0] + other.ambient_[0] ) / 2, (ambient_[1] + other.ambient_[1] ) / 2, (ambient_[2] + other.ambient_[2] ) / 2, (ambient_[3] + other.ambient_[3] ) / 2 );
    mat.setDiffuse( (diffuse_[0] + other.diffuse_[0] ) / 2, (diffuse_[1] + other.diffuse_[1] ) / 2, (diffuse_[2] + other.diffuse_[2] ) / 2, (diffuse_[3] + other.diffuse_[3] ) / 2 );
    mat.setSpecular( (specular_[0] + other.specular_[0] ) / 2, (specular_[1] + other.specular_[1] ) / 2, (specular_[2] + other.specular_[2] ) / 2, (specular_[3] + other.specular_[3] ) / 2 );
    mat.setShininess( ( shininess_[0] + other.shininess_[0] ) / 2 );
    return mat;
  }
  Material interpolate(const Material& other, float t = 0.5) const
  {
    if (t > 1.0 || t < 0.0) return Material();
    Material mat;
    mat.setAmbient( ambient_[0] * (1.0 - t) + other.ambient_[0] * t , ambient_[1] * (1.0 - t) + other.ambient_[1] * t , ambient_[2] * (1.0 - t) + other.ambient_[2] * t , ambient_[3] * (1.0 - t) + other.ambient_[3] * t );
    mat.setDiffuse( diffuse_[0] * (1.0 - t) + other.diffuse_[0] * t, diffuse_[1] * (1.0 - t) + other.diffuse_[1] * t, diffuse_[2] * (1.0 - t) + other.diffuse_[2] * t, diffuse_[3] * (1.0 - t) + other.diffuse_[3] * t );
    mat.setSpecular( specular_[0] * (1.0 - t) + other.specular_[0] * t, specular_[1] * (1.0 - t) + other.specular_[1] * t, specular_[2] * (1.0 - t) + other.specular_[2] * t, specular_[3] * (1.0 - t) + other.specular_[3] * t );
    mat.setShininess( shininess_[0] * (1.0 - t) + other.shininess_[0] * t );
    return mat;
  }

protected:
  float ambient_[4];
  float diffuse_[4];
  float specular_[4];
  float shininess_[4]; // need only 1 component, but have 4 for better memory alignment
};

#ifdef DEBUG
#include <iostream>

inline std::ostream& operator << (std::ostream& strm, const Material& m)
{
  strm << "Ambient : " << m.ambient()[0] << " " << m.ambient()[1] << " " << m.ambient()[2] << " " << m.ambient()[3] << std::endl
       << "Diffuse : " << m.diffuse()[0] << " " << m.diffuse()[1] << " " << m.diffuse()[2] << " " << m.diffuse()[3] << std::endl
       << "Specular : " << m.specular()[0] << " " << m.specular()[1] << " " << m.specular()[2] << " " << m.specular()[3] << std::endl
       << "Shininess : " << m.shininess() << std::endl;
  return strm;
}

#endif

#endif // MATERIAL_HEADER_VIZMF_PROJECT
